#pragma once
#include <iostream>
#include <unordered_map>
#include "Connection.hpp"
#include <sys/epoll.h>
#include "Epoller.hpp"

using namespace EpollModuo;

//使用epoll进行等待 并且 使用非阻塞式轮询读取数据


static const int gmaxevents = 64;
#define EPOLL_BLOCK  -1

class TcpServer
{
public:    
    TcpServer():_isrunning(false),_timeout(EPOLL_BLOCK)
    {
        _epoller.InitEpoller();//初始化epoller
    }
    ~TcpServer(){}


    bool IsConnectionExits(int sockfd)
    {
        auto iter = _connections.find(sockfd);
        if(iter == _connections.end())
            return false;

        return true;
    }
    
    //添加新链接
    void AddConnection(Connection* conn)
    {
        if(!conn)
            return;

        if(IsConnectionExits(conn->SockFD()))//查看该Connection是否存在
            return; //存在就返回
//将新的连接进行处理：
// 1. tcpserver对连接进行保存
// 2. epoll等待（epoller）阻塞式读取数据

//1.添加到map中
        _connections.insert(std::make_pair(conn->SockFD(),conn));
        lg.LogMessage(Info,"add a new connection success,sockfd:%d\n",conn->SockFD());

//2.添加到_epoller中
        _epoller.AddEvent(conn->SockFD(),conn->SockEvent());
    }

    // void loop()
    void Dispatcher()//事件派发器
    {
        _isrunning = true;
        while(_isrunning)
        {
            //... 处理就绪事件
            LoopOnce(_timeout);
        }
        _isrunning = false;
    }


//1. 进行事件派发(也就是进行一次处理数据，11而此处不再对数据进行处理了
//2. 而是将处理数据交出去，实现一定的解耦
//3. 也就是此处只对新链接的发生了什么事件进行判断
//4. 判断完后调用连接中自己的对应的事件的处理回调函数！)
    void LoopOnce(int timeout) 
    {
        int n = _epoller.Wait(_revs,gmaxevents,timeout);
        //传进去的revs会存着已经就绪的事件出来

        for(int i = 0;i < n ;i++)
        {
            int sockfd = _revs[i].data.fd;
            int events = _revs[i].events;


//将出现的问题全部加上 输入、输出事件，当去执行时让他转化成IO错误
            if(events & EPOLLERR)//文件描述符发生错误;
                events |= (EPOLLIN |  EPOLLOUT);
            
            if(events & EPOLLHUP)//文件描述符被挂断;
                events |= (EPOLLIN |  EPOLLOUT);
           

//读就绪：
            if(events & EPOLLIN)
            {

                if(IsConnectionExits(sockfd))
                {
                    if(_connections[sockfd]->_recver != nullptr)
                    {

                        _connections[sockfd]->_recver(_connections[sockfd]);
                    }
                }
            }

//写就绪
            if(events & EPOLLOUT)
            {
                lg.LogMessage(Debug,"EPOLLOUT\n");

                if(IsConnectionExits(sockfd))
                {
                    if(_connections[sockfd]->_sender)
                    {
                        _connections[sockfd]->_sender(_connections[sockfd]);
                    }
                }
            }
        }
        _epoller.DebugFdList();


    }

    void EnableReadWrite(int sockfd,bool read,bool write)
    {
        if(IsConnectionExits(sockfd))//判断是否存在
        {
            uint32_t event = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET;
            
            _connections[sockfd]->SetEvent(event);//设置Connection的event

            //将event设置到内核
            _epoller.ModEvent(sockfd,event);
        }
    }

    void RemoveConnection(int sockfd)
    {
        if(IsConnectionExits(sockfd)){
            _connections[sockfd]->SetEvent(0);//将该连接的事件清零
            _connections.erase(sockfd);//清楚TcpServer中的数据
            _epoller.DelEvent(sockfd);//清除epoller内核中的数据
        }
    }
private:
    int _sockfd;//文件描述符
    
    Epoller _epoller;

    std::unordered_map<int,Connection*> _connections;


    bool _isrunning;
    int _timeout;
    struct epoll_event _revs[gmaxevents];
    //events
    //event_data_t data
        //fd
        //回调函数（事件发生的触发器，告知事件就绪）
        //需要等待的事件的红黑树
        //就绪队列
};